package com.bryanbibat.flashcards.spring;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;

public class DeckControllerTests {

  private DeckController controller;

  @Before
  public void setup() {
    controller = new DeckController();
    controller.deckService = new FakeDeckService();
  }

  @Test
  public void list_all() {
    ModelMap model = new ModelMap();
    assertEquals("decks", controller.listDecks(model));
  }

  @Test
  public void go_to_new() {
    ModelMap model = new ModelMap();
    assertEquals("newDeck", controller.newDeck(model));
  }
  
  @Test
  public void normal_data() {
    Deck deck = new Deck();
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
    		"[ \"3\", \"3\"], [ \"4\", \"4\"], [ \"5\", \"5\"]," +
    		"[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", \"8\"]," +
    		"[ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertFalse(bindingResult.hasErrors());
  }
  
  @Test
  public void test_garbage_data() {
    Deck deck = new Deck();
    deck.setJsonData(" asd asd ");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertEquals("not.valid.json", bindingResult.getFieldError("jsonData").getCode());
  }
  
  @Test
  public void test_too_few() {
    Deck deck = new Deck();
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], [ \"4\", \"4\"], [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", \"8\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertEquals("too.few.cards", bindingResult.getFieldError("jsonData").getCode());
  }

  @Test
  public void not_valid_card() {
    Deck deck = new Deck();
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], a,  [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", \"8\"]," +
        "[ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertEquals("not.valid.card", bindingResult.getFieldError("jsonData").getCode());
    assertEquals(5, bindingResult.getFieldError("jsonData").getArguments()[0]);
  }
  
  @Test
  public void test_too_few_for_one_card() {
    Deck deck = new Deck();
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], [ \"4\" ], [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", \"8\"], [ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertEquals("card.too.small", bindingResult.getFieldError("jsonData").getCode());
    assertEquals(5, bindingResult.getFieldError("jsonData").getArguments()[0]);
  }
  
  @Test
  public void test_too_many_for_one_card() {
    Deck deck = new Deck();
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], [ \"4\", \"4\", \"4\" ], [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", \"8\"], [ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertFalse(bindingResult.hasErrors());
  }
  
  @Test
  public void duplicate_column_one() {
    Deck deck = new Deck();
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], [ \"4\", \"4\" ], [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ x, \"8\"], [ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertEquals("duplicate.value", bindingResult.getFieldError("jsonData").getCode());
    assertEquals(9, bindingResult.getFieldError("jsonData").getArguments()[0]);
  }

  @Test
  public void duplicate_column_two() {
    Deck deck = new Deck();
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], [ \"4\", \"4\" ], [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", x], [ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator();
    validator.validateData(deck.getJsonData(), bindingResult);
    assertEquals("duplicate.value", bindingResult.getFieldError("jsonData").getCode());
    assertEquals(9, bindingResult.getFieldError("jsonData").getArguments()[0]);
  }
  
  @Test
  public void id_alphanumeric() {
    Deck deck = new Deck();
    deck.setId("id_0");
    deck.setTitle("id");
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], [ \"4\", \"4\"], [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", \"8\"]," +
        "[ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator(new FakeDeckService(), false);
    validator.validate(deck, bindingResult);
    assertFalse(bindingResult.hasErrors());
  }
  
  @Test
  public void id_alphanumeric_break() {
    Deck deck = new Deck();
    deck.setId(" ");
    deck.setTitle("id");
    deck.setJsonData("[[ \"x\", \"x\"],  [ \"1\", \"1\"], [ \"2\", \"2\"], " +
        "[ \"3\", \"3\"], [ \"4\", \"4\"], [ \"5\", \"5\"]," +
        "[ \"6\", \"6\"], [ \"7\", \"7\"], [ \"8\", \"8\"]," +
        "[ \"9\", \"9\"]]");    
    BindingResult bindingResult = new BeanPropertyBindingResult(deck, "deck");
    DeckValidator validator = new DeckValidator(new FakeDeckService(), false);
    validator.validate(deck, bindingResult);
    assertEquals("must.be.alphanumeric", bindingResult.getFieldError("id").getCode());
    assertTrue(bindingResult.hasErrors());
  }
  

}
